#pragma once

#include <iostream>
#include <string>
#include <cstdarg>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define Info 0
#define Debug 1
#define Warning 2
#define Error 3
#define Fatal 4

#define Screen 1
#define Onefile 2
#define Classfile 3

#define SIZE 1024

// std::string defaultPath = "log.txt";
#define DefaultPath "log.txt"

class Log
{
public:
    Log()
        : method_(Screen)
    {
        path_ = "./"; // 路径需是存在的
    }

    void Enable(int method)
    {
        method_ = method;
    }

    std::string LevelToString(int level)
    {
        switch (level)
        {
        case Info:
            return "Info";
        case Debug:
            return "Debug";
        case Warning:
            return "Warning";
        case Error:
            return "Error";
        case Fatal:
            return "Fatal";
        default:
            return "nothing";
        }
    }

    void PrintLog(int level, const std::string &contex) // 可以加上&
    {
        switch (method_)
        {
        case Screen:
            std::cout << contex << std::endl;
            break;
        case Onefile:
            PrintOneFile(DefaultPath, contex);
            break;
        case Classfile:
            PrintClassfile(level, contex);
            break;
        default: // 不匹配时直接退出
            break;
        }
    }

    void PrintOneFile(const std::string &fileName, const std::string &contex) // 可以加上&
    {
        std::string logFileName = path_ + fileName;
        int fd = open(logFileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
        if (fd < 0)
        {
            perror("open");
            return;
        }
        write(fd, contex.c_str(), contex.size());
        close(fd);
    }

    void PrintClassfile(int level, const std::string &contex)
    {
        std::string logFileName = DefaultPath;
        logFileName += '.';
        logFileName += LevelToString(level);
        PrintOneFile(logFileName, contex);
    }

    void operator()(int level, const char *format, ...)
    {
        char leftBuffer[SIZE];
        time_t te = time(nullptr);
        struct tm *tm = localtime(&te);
        snprintf(leftBuffer, SIZE, "[%s] [%d/%d/%d %d:%d:%d]", LevelToString(level).c_str(),
                 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);

        va_list vl;
        va_start(vl, format);
        char rightBuffer[SIZE];
        vsnprintf(rightBuffer, SIZE, format, vl);
        va_end(vl);

        std::string ret = leftBuffer;
        ret += " ";
        ret += rightBuffer;
        PrintLog(level, ret);
    }

    // void Test()
    // {
    //     for(int i = 0; i < 5; ++i)
    //     {
    //         std::cout<<LevelToString(i)<<std::endl;
    //     }
    //     for(int i = 1; i < 4; ++i)
    //     {
    //         std::cout<<method_<<std::endl;
    //         Enable(i + 1);
    //     }
    // }

private:
    int method_;
    std::string path_;
};